﻿using CPPEI.Coolzon.Event.Core;
using CPPEI.Coolzon.Event.NCL;
using CPPEI.Coolzon.UI;
using CPPEI.Coolzon.UI.Data;
using CPPEI.Coolzon.UI.Event;
using CPPEI.Coolzon.UI.Views;
using CPPEI.Coolzon.UI.Views.Windows;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace CPPEI.Coolzon.Theme.Default.MainViewControl
{
    /// <summary>
    /// SceneView.xaml 的交互逻辑
    /// </summary>
    public partial class SceneView : UserControl
    {
        private double _scaleX;
        private double _scaleY;
        private Point _startPoint;
        private Point _endPoint;

        private DispatcherTimer _dispatcherTimer;
        private BorderWindow _borderWindow;
        private Hook _hook;
        /// <summary>
        /// 屏幕坐标
        /// </summary>
        private Point _oldPoint;
        //private Label OldBorder;
        private bool _isLongPress;
        private bool _canMove = true;
        private bool _borderStop = false;
        private Part _screenPart;
        private bool _isStartMagnifier = false;
        private DateTime _startTimer;
        private bool _isStartPen = false;
        private bool _isResetScene = false;
        //private bool _isFirstLoad;
        //private int _leftRight;

        private VisualBrush partBrush;
        private ImageSource partImageSource;
        public Metadata.Scene _Scene { get; set; }

        /// <summary>
        /// 鼠标是否是按下模式，如果true则不接收场景更新事件了
        /// </summary>
        private bool _isMouseDownState = false;
        private UIEventType _eventType = UIEventType.None;
        private Point _mousePos;
        private double _moveOffsetXY = 20;
        private List<Line> _lineList = new List<Line>();
        public SceneView()
        {
            InitializeComponent();

            this.MouseDown += SceneView_MouseDown;
            this.MouseMove += SceneView_MouseMove;
            this.MouseUp += SceneView_MouseUp;

            this.TouchDown += SceneView_TouchDown;
            this.TouchUp += SceneView_TouchUp;

            _hook = new Hook();
            _hook.MouseLeftButtonMove += hook_MouseLeftButtonMove;
            _hook.MouseLeftButtonUp += hook_MouseLeftButtonUp;
        }
        #region 方法
        private void SetPartImageSource()
        {
            if (partImageSource == null || _isResetScene)
            {
                partImageSource = _screenPart.ProjectionToImage();
            }
            _isResetScene = false;
            canvas.Background = new ImageBrush(partImageSource);
        }
        private bool IsMouseMoving(Point oldPoint, Point newPoint)
        {
            Point screenPoint = PointToScreen(newPoint);
            double oldPi = Math.Sqrt(Math.Pow(oldPoint.X, 2) + Math.Pow(oldPoint.Y, 2));
            double newPi = Math.Sqrt(Math.Pow(screenPoint.X, 2) + Math.Pow(screenPoint.Y, 2));
            if (Math.Abs(oldPi - newPi) > 10) return true;
            return false;
        }

        private void Down(Point point)
        {
            _isMouseDownState = true;
            _oldPoint = PointToScreen(point);
            AreaPart area = GetAreaPartAtPoint(point.X, point.Y);
            if (_Scene.IsAllowSwapArea)
            {
                SetDispatchTime(area);
            }
            ScollToPos(point);
        }

        private void Up(Point point)
        {
            _isMouseDownState = false;
            StopDispatchTime();
            if (_borderWindow != null)
            {
                AreaPart target = GetAreaPartAtPoint(point.X, point.Y, 1);
                AreaPart source = _borderWindow.Tag as AreaPart;
                Swap(source, target);
                _canMove = true;
            }
            CloseBorderWindow();

            canvas.Background = partBrush;
        }
        private void Move(double x, double y)
        {
            if (_borderWindow == null) return;
            if (_oldPoint != null)
            {
                SetBorderWindowPoint();
            }
            //_leftRight = x - _oldPoint.X > 0 ? 1 : 0;
            _oldPoint = new Point(x, y);
        }
        /// <summary>
        /// 设置蒙版位置
        /// </summary>
        /// <returns></returns>
        private void SetBorderWindowPoint()
        {
            double tempLeft = _oldPoint.X - _borderWindow.Width / 2;
            double tempTop = _oldPoint.Y - _borderWindow.Height / 2;

            if (tempLeft < _startPoint.X)
            {
                _borderWindow.Left = _startPoint.X;
            }
            else if (tempLeft + _borderWindow.Width > _endPoint.X)
            {
                _borderWindow.Left = _endPoint.X - _borderWindow.Width;
            }
            else
            {
                _borderWindow.Left = tempLeft;
            }
            if (tempTop + _borderWindow.Height > _endPoint.Y)
            {
                _borderWindow.Top = _endPoint.Y - _borderWindow.Height;
            }
            else
            {
                _borderWindow.Top = tempTop;
            }
        }
        private void Swap(AreaPart source, AreaPart target)
        {
            if (source != null && target != null)
            {
                //是否允许区域互换
                if (_Scene.IsAllowSwapArea)
                {
                    Common.EventBus.Instance.Publish(new SwapAreaEvent(_Scene.Name, source.Name, target.Name));
                }
            }
        }
        /// <summary>
        /// 根据坐标获取区域
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="fromScreen">为1时，x,y代表屏幕坐标</param>
        /// <returns></returns>
        private AreaPart GetAreaPartAtPoint(double x, double y, int fromScreen = 0)
        {
            CPPEI.Coolzon.UI.Views.RenderView renderView = (CPPEI.Coolzon.UI.Views.RenderView)UI.UIContext.Current.RenderView;
            ScenePart scenePart = (ScenePart)renderView.GetCurrentPart();
            Point elementPoint = new Point(x, y);
            if (fromScreen == 1)
            {
                elementPoint = this.PointFromScreen(new Point(x, y));
            }
            Point scalePoint = new Point(elementPoint.X / _scaleX, elementPoint.Y / _scaleY);
            AreaPart area = (AreaPart)scenePart.GetRootArea(scalePoint);

            if (_borderWindow != null && area != null)
            {
                AreaPart sourceArea = _borderWindow.Tag as AreaPart;
                int leftRight = sourceArea.XLeft < area.XLeft ? 1 : 0;
                if (leftRight == 1)
                {
                    if (elementPoint.X < (area.XLeft + area.Width / 2) * _scaleX)
                    {
                        area = scenePart.GetLeftRootArea(area);
                    }
                }
                else
                {
                    if (elementPoint.X > (area.XLeft + area.Width / 2) * _scaleX)
                    {
                        area = scenePart.GetRightRootArea(area);
                    }
                }
            }
            return area;
        }

        private void CreateScaleView(AreaPart area)
        {
            if (area == null)
            {
                return;
            }

            _startPoint = PointToScreen(new Point(0, 0));
            _endPoint = PointToScreen(new Point(this.ActualWidth, this.ActualHeight));

            _borderWindow = new BorderWindow();
            _borderWindow.Width = area.ActualWidth * _scaleX;
            _borderWindow.Height = area.ActualHeight * _scaleY;
            _borderWindow.Left = _oldPoint.X - _borderWindow.Width / 2;
            _borderWindow.Top = _oldPoint.Y - _borderWindow.Height / 2;
            _borderWindow.ShowInTaskbar = false;
            _borderWindow.Topmost = true;

            //冻结canvas
            //canvas.Background = new ImageBrush(_screenPart.ProjectionToImage());

            _borderWindow.Show();

            _hook.SetMouseHook();
            _borderWindow.Tag = area;

            _dispatcherTimer.IsEnabled = false;
        }
        private void ScollToPos(Point point)
        {
            double borderLeft = point.X - _border.Width / 2;
            double borderTop = point.Y - _border.Height / 2;

            SetBorderRect(ref borderLeft, ref borderTop);

            double tLeft = borderLeft / _scaleX;
            double tTop = borderTop / _scaleY;

            CPPEI.Coolzon.UI.Views.RenderView renderView = (CPPEI.Coolzon.UI.Views.RenderView)UI.UIContext.Current.RenderView;
            renderView.ScrollToPos(tLeft, tTop);
        }

        private void SetBorderRect(ref double borderLeft, ref double borderTop)
        {
            if (borderLeft + _border.Width > this.ActualWidth)
            {
                borderLeft = this.ActualWidth - _border.Width;
            }
            if (borderTop + _border.Height > this.ActualHeight)
            {
                borderTop = this.ActualHeight - _border.Height;
            }
            if (borderLeft < 0.0)
            {
                borderLeft = 0.0;
            }
            if (borderTop < 0.0)
            {
                borderTop = 0.0;
            }
        }
        public void SetSceneView()
        {
            CPPEI.Coolzon.UI.Views.RenderView renderView = (CPPEI.Coolzon.UI.Views.RenderView)UI.UIContext.Current.RenderView;
            _screenPart = renderView.GetCurrentPart();
            _scaleX = canvas.ActualWidth / _screenPart.XWidth;
            _scaleY = canvas.ActualHeight / _screenPart.XHeight;

            if (_screenPart != null)
            {
                if (_Scene != (_screenPart as ScenePart).SceneMatadata)
                {
                    _Scene = (_screenPart as ScenePart).SceneMatadata;

                    partBrush = new VisualBrush(_screenPart);
                    RenderOptions.SetCachingHint(partBrush, CachingHint.Cache);
                    RenderOptions.SetCacheInvalidationThresholdMaximum(partBrush, 2.0);
                    RenderOptions.SetCacheInvalidationThresholdMinimum(partBrush, 0.5);
                    partBrush.Stretch = Stretch.Fill;

                    canvas.Background = partBrush;

                    partImageSource = null;
                }

                AddLine();

                Rect viewRect = renderView.GetViewRegionInScene();

                double borderLeft = viewRect.Left * _scaleX;
                double borderTop = viewRect.Top * _scaleY;
                SetBorderRect(ref borderLeft, ref borderTop);
                Canvas.SetLeft(_border, borderLeft);
                Canvas.SetTop(_border, borderTop);
                _border.Width = viewRect.Width * _scaleX;
                _border.Height = viewRect.Height * _scaleY;
            }
        }

        private void AddLine()
        {
            ClearLines();

            List<Part> partList = (_screenPart as ScenePart).GetPartList();
            foreach (Part part in partList)
            {
                double partLeft = Canvas.GetLeft(part) * _scaleX;
                double partWidth = part.ActualWidth * _scaleX;
                double partHeight = part.ActualHeight * _scaleY;

                Line line = new Line();

                line.X1 = partLeft + partWidth;
                line.Y1 = Canvas.GetTop(part) * _scaleY;

                line.X2 = line.X1;
                line.Y2 = line.Y1 + partHeight;

                line.Stroke = new SolidColorBrush(Colors.White);
                line.StrokeDashArray = new DoubleCollection { 3, 2 };
                line.StrokeThickness = 3;
                canvas.Children.Add(line);

                _lineList.Add(line);
            }
        }

        private void ClearLines()
        {
            foreach (Line line in _lineList)
            {
                canvas.Children.Remove(line);
            }
            _lineList.Clear();
        }

        private void SetMouseUp()
        {
            if (_isMouseDownState)
            {
                _eventType = UIEventType.None;
                _isMouseDownState = false;
                StopDispatchTime();
                //if (_isStartMagnifier)
                //{
                //    Common.EventBus.Instance.Publish(new UI.Event.MagnifySceneEvent { IsEnable = false });
                //}
                //else if (_isStartPen)
                //{
                //    Common.EventBus.Instance.Publish(new UI.Event.ShowLaserPointerEvent { IsShow = false });
                //}
                CloseBorderWindow();
            }
        }
        private void SetMouseDown()
        {
            if (!_isMouseDownState)
            {
                Point pos = System.Windows.Input.Mouse.GetPosition(this);
                _mousePos = pos;
                _eventType = UIEventType.Mouse;
                _isMouseDownState = true;

                if (!_isStartMagnifier && !_isStartPen)
                    Down(pos);
            }
        }

        private void SetMouseMove()
        {
            if (_isMouseDownState && _eventType != UIEventType.None)
            {
                Point pos = System.Windows.Input.Mouse.GetPosition(this);
                if (_isStartMagnifier || _isStartPen)
                {
                    if (_startTimer == DateTime.MinValue)
                    {
                        _startTimer = DateTime.Now;
                    }
                    else
                    {
                        if ((DateTime.Now - _startTimer).Milliseconds >= 100)
                        {
                            _startTimer = DateTime.Now;
                            if (_isStartMagnifier)
                            {
                                NCLEventBus.Publish(new NCLShowMagnifierEvent
                                (
                                    true,_Scene.Name,1.5d,pos.X / _scaleX,pos.Y / _scaleY,400,0.1
                                ));
                            }
                            else if (_isStartPen)
                            {
                                NCLEventBus.Publish(new NCLShowLaserPointerEvent
                                (
                                    true,_Scene.Name,0,pos.X / _scaleX,pos.Y / _scaleY,10,0.1
                                ));
                            }
                        }
                    }
                }
                else
                {
                    if (!_canMove) return;


                    if (!_isLongPress && IsMouseMoving(_oldPoint, pos))
                    {
                        StopDispatchTime();
                    }

                    if (Math.Abs(pos.X - _mousePos.X) > _moveOffsetXY
                        || Math.Abs(pos.Y - _moveOffsetXY) > _moveOffsetXY)
                    {
                        _mousePos = pos;
                        ScollToPos(pos);
                    }
                }
            }
        }
        private void CloseBorderWindow()
        {
            _hook.UnLoadHook();
            if (_borderWindow != null)
            {
                _borderWindow.Close();
                _borderWindow = null;
            }
        }
        private void SetDispatchTime(object sender)
        {
            if (_dispatcherTimer == null)
            {
                _dispatcherTimer = new DispatcherTimer();
                _dispatcherTimer.Interval = TimeSpan.FromSeconds(1);
                _dispatcherTimer.Tick += dispatcherTimer_Tick;
                _dispatcherTimer.IsEnabled = true;
            }
            _dispatcherTimer.Start();
            _dispatcherTimer.Tag = sender;
        }
        private void StopDispatchTime()
        {
            if (_dispatcherTimer != null)
            {
                _dispatcherTimer.IsEnabled = false;
                _dispatcherTimer.Stop();
                _hook.UnLoadHook();
            }
        }
        void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            SetPartImageSource();
            _isLongPress = true;
            _dispatcherTimer.IsEnabled = false;
            CreateScaleView((AreaPart)_dispatcherTimer.Tag);
            _isLongPress = false;
            _canMove = false;
        }
        #endregion

        #region 钩子事件
        void hook_MouseLeftButtonUp(double x, double y)
        {
            Up(new Point(x, y));
        }

        void hook_MouseLeftButtonMove(double x, double y)
        {
            Move(x, y);
        }
        #endregion

        #region 事件总线处理方法
        [Common.Subscribe]
        public void SceneUpdated(SceneUpdateEvent @event)
        {
            SetSceneView();
            if (@event.Reason == SceneUpdateReason.ResetScene)
            {
                _isResetScene = true;
            }
        }
        [Common.Subscribe]
        public void SceneVewUpdated(AnimationEndEvent @event)
        {
            SetSceneView();
        }
        [Common.Subscribe]
        public void SwapAreaCompleted(SwapAreaCompletedEvent @event)
        {
            SetSceneView();
            partImageSource = _screenPart.ProjectionToImage();
        }
        [Common.Subscribe]
        public void OnOpened(CoreOpenSceneCompletedEvent @event)
        {
            if (@event.SwitchMode == SwitchMode.Pop)
            {
                this.IsEnabled = false;
            }
            else if (@event.SwitchMode == SwitchMode.Replace)
            {
                this.IsEnabled = true;
            }
        }
        [Common.Subscribe]
        public void OnStartMagnifier(StartMagnifierEvent @event)
        {
            _isStartMagnifier = true;
        }
        [Common.Subscribe]
        public void OnCloseMagnifier(CloseMagnifierEvent @event)
        {
            _isStartMagnifier = false;
        }
        [Common.Subscribe]
        public void OnStartPen(StartPenEvent @event)
        {
            _isStartPen = true;
        }

        [Common.Subscribe]
        public void OnClosePen(ClosePenEvent @event)
        {
            _isStartPen = false;
        }
        enum UIEventType
        {
            None,
            Mouse,
            Touch,
        }
        #endregion

        #region 场景视图事件
        /// <summary>
        /// 鼠标移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SceneView_MouseMove(object sender, RoutedEventArgs e)
        {
            SetMouseMove();
        }
        /// <summary>
        /// 鼠标按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SceneView_MouseDown(object sender, RoutedEventArgs e)
        {
            SetMouseDown();
        }

        /// <summary>
        /// 鼠标弹起
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SceneView_MouseUp(object sender, MouseButtonEventArgs e)
        {
            SetMouseUp();
        }

        void SceneView_TouchDown(object sender, TouchEventArgs e)
        {
            //SetPartImageSource();
            if (!_isMouseDownState)
            {
                _mousePos = e.GetTouchPoint(this).Position;

                _eventType = UIEventType.Touch;
                _isMouseDownState = true;
                System.Diagnostics.Debug.WriteLine("Touch down");

                if (!_isStartMagnifier && !_isStartPen)
                    Down(e.GetTouchPoint(this).Position);
            }
        }

        void SceneView_TouchUp(object sender, TouchEventArgs e)
        {
            if (_isMouseDownState)
            {
                _eventType = UIEventType.None;
                _isMouseDownState = false;
                System.Diagnostics.Debug.WriteLine("Touch up");

                if (!_isStartMagnifier && !_isStartPen)
                    Up(PointToScreen(e.GetTouchPoint(this).Position));
                //if (_isStartMagnifier)
                //{
                //    Common.EventBus.Instance.Publish(new UI.Event.MagnifySceneEvent { IsEnable = false });
                //}
                //else if (_isStartPen)
                //{
                //    Common.EventBus.Instance.Publish(new UI.Event.ShowLaserPointerEvent { IsShow = false });
                //}
            }
            canvas.Background = partBrush;
        }
        #endregion

        #region 区域框事件
        void _border_MouseUp(object sender, MouseButtonEventArgs e)
        {
            _border.ReleaseMouseCapture();
            Panel.SetZIndex(_border, 1);
            SetMouseUp();
            canvas.Background = partBrush;
            e.Handled = true;
        }

        void _border_MouseMove(object sender, MouseEventArgs e)
        {
            SetMouseMove();
            e.Handled = true;
        }

        void _border_MouseDown(object sender, RoutedEventArgs e)
        {
            Panel.SetZIndex(_border, 2);
            _border.CaptureMouse();
            SetMouseDown();
            SetPartImageSource();
            e.Handled = true;
        }

        private void _border_TouchDown(object sender, TouchEventArgs e)
        {
            Panel.SetZIndex(_border, 2);
            SetMouseDown();
            SetPartImageSource();
            e.Handled = true;
        }

        private void _border_TouchMove(object sender, TouchEventArgs e)
        {
            SetMouseMove();
            e.Handled = true;
        }

        private void _border_TouchUp(object sender, TouchEventArgs e)
        {
            Panel.SetZIndex(_border, 1);
            SetMouseUp();
            canvas.Background = partBrush;
            e.Handled = true;
        }
        #endregion

        //#region 放大镜事件
        //private void MagnifierDown()
        //{
        //    _isMouseDownState = true;
        //    Panel.SetZIndex(magnifier, 2);
        //    SetPartImageSource();
        //}
        //private void MagnifierMove()
        //{
        //    if (_isMouseDownState && System.Windows.Input.Mouse.LeftButton == MouseButtonState.Pressed)
        //    {
        //        Point point = System.Windows.Input.Mouse.GetPosition(this);
        //        double left = point.X - magnifier.Width / 2;
        //        double top = point.Y - magnifier.Height / 2;

        //        //放大镜不得越过视图区域
        //        if (left < 0)
        //        {
        //            left = 0;
        //        }
        //        if (left + magnifier.Width > this.ActualWidth)
        //        {
        //            left = this.ActualWidth - magnifier.Width;
        //        }
        //        if (top < 0)
        //        {
        //            top = 0;
        //        }
        //        if (top + magnifier.Height > this.ActualHeight)
        //        {
        //            top = this.ActualHeight - magnifier.Height;
        //        }

        //        Canvas.SetLeft(magnifier, left);
        //        Canvas.SetTop(magnifier, top);

        //        Common.EventBus.Instance.Publish(new UI.Event.MagnifySceneEvent
        //        {
        //            IsEnable = true,
        //            DestPointX = point.X / _scaleX,
        //            DestPointY = point.Y / _scaleY
        //        });
        //    }
        //}
        //private void MagnifierUp()
        //{
        //    _isMouseDownState = false;
        //    Panel.SetZIndex(magnifier, 1);
        //    Canvas.SetLeft(magnifier, 0.0);
        //    Canvas.SetTop(magnifier, this.ActualHeight - magnifier.Width);
        //    Common.EventBus.Instance.Publish(new UI.Event.MagnifySceneEvent { IsEnable = false });
        //    canvas.Background = partBrush;
        //}
        //private void magnifier_MouseDown(object sender, RoutedEventArgs e)
        //{
        //    MagnifierDown();
        //    magnifier.CaptureMouse();
        //    e.Handled = true;
        //}
        //private void magnifier_MouseMove(object sender, RoutedEventArgs e)
        //{
        //    MagnifierMove();
        //    e.Handled = true;
        //}

        //private void magnifier_MouseUp(object sender, RoutedEventArgs e)
        //{
        //    MagnifierUp();
        //    magnifier.ReleaseMouseCapture();
        //    e.Handled = true;
        //}

        //private void magnifier_TouchDown(object sender, TouchEventArgs e)
        //{
        //    MagnifierDown();
        //    e.Handled = true;
        //}

        //private void magnifier_TouchMove(object sender, TouchEventArgs e)
        //{
        //    MagnifierMove();
        //    e.Handled = true;
        //}

        //private void magnifier_TouchUp(object sender, TouchEventArgs e)
        //{
        //    MagnifierUp();
        //    e.Handled = true;
        //}
        //#endregion
    }
}
